/*
 * test_libmana
 * Copyright (c) 2011 Shun Moriya <shun@mnu.sakura.ne.jp>
 *
 * The MIT License
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include "test_libmana.h"
#include <libmana.h>
#include <tinytest.h>
#include <string.h>

static void test_mana_array()
{
	int value = 19720126;

	mana_array* self = mana_array_create(1);

	mana_array_set(self, 9, &value);
	tinytest_assert(mana_array_get(self, 9) == &value);
	tinytest_assert(mana_array_get_size(self) == 10);

	mana_array_append(self, &value);
	tinytest_assert(mana_array_get(self, 10) == &value);
	tinytest_assert(mana_array_get_size(self) == 11);

	mana_array_resize(self, 20);
	tinytest_assert(mana_array_get_size(self) == 11);

	{
		mana_stream* stream = mana_stream_create();

		mana_array_serialize(self, stream);

		mana_array* duplicated = mana_array_create(0);
		mana_array_deserialize(duplicated, stream);
		tinytest_assert(mana_array_compare(self, duplicated) == 0);
		mana_array_destroy(duplicated);

		mana_stream_destroy(stream);
	}

	mana_array_resize(self, 5);
	tinytest_assert(mana_array_get_size(self) == 5);

	mana_array_destroy(self);
}

static void test_mana_buffer()
{
	unsigned char test_data[16] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf };

	mana_buffer* self = mana_buffer_create();

	tinytest_assert(mana_buffer_get_buffer(self) == NULL);
	tinytest_assert(mana_buffer_push(self, test_data, sizeof(test_data)));
	tinytest_assert(mana_buffer_get_used_size(self) == sizeof(test_data));
	tinytest_assert(mana_buffer_get_allocated_size(self));
	tinytest_assert(mana_buffer_get_buffer(self) != NULL);

	mana_buffer_destroy(self);
}

static void test_mana_frame()
{
	mana_frame* self = mana_frame_create();

	extern void mana_frame_clear(mana_frame* self);

	mana_frame_allocate(self, 1000);
	tinytest_assert(mana_frame_get_size(self) == 1000);

	mana_frame_release(self, 50);
	tinytest_assert(mana_frame_get_size(self) == 1000 - 50);

	mana_frame_set_size(self, 500);
	tinytest_assert(mana_frame_get_size(self) == 500);

	unsigned char* buffer = (unsigned char*)mana_frame_get_address(self, 500);
	for(size_t i = 0; i < 500; i++)
	{
		buffer[i] = (unsigned char)i;
	}

	{
		mana_stream* stream = mana_stream_create();

		mana_frame_serialize(self, stream);

		mana_frame* duplicated = mana_frame_create();
		mana_frame_deserialize(duplicated, stream);
		tinytest_assert(mana_frame_compare(self, duplicated) == 0);
		mana_frame_destroy(duplicated);

		mana_stream_destroy(stream);
	}

	mana_frame_destroy(self);
}

static void test_mana_hash()
{
	mana_hash* self = mana_hash_create();

	mana_hash_set(self, "hoge", self);
	tinytest_assert(mana_hash_get(self, "hoge") == self);

	mana_hash_set(self, "foo", self);
	tinytest_assert(mana_hash_test(self, "foo"));
	tinytest_assert(mana_hash_get(self, "foo") == self);

	{
		mana_hash_iterator iterator;
		mana_hash_iterator_rewind(&iterator);
		while(mana_hash_iterator_hash_next(self, &iterator))
		{
			const char* name = mana_hash_iterator_get_name(&iterator);
			void* data = mana_hash_iterator_get_value(&iterator);

			tinytest_print("%s: %p\n", name, data);
		}
	}

	mana_hash_erase(self, "foo");
	tinytest_assert(!mana_hash_test(self, "foo"));
	tinytest_assert(mana_hash_get(self, "foo") == NULL);

	mana_hash_set(self, "foo", self);
	tinytest_assert(mana_hash_get(self, "foo") == self);

	{
		mana_hash* duplicate = mana_hash_create();
		mana_hash_duplicate(duplicate, self);

		tinytest_assert(mana_hash_compare(duplicate, self));

		mana_hash_destroy(duplicate);
	}

	mana_hash_clear(self);
	tinytest_assert(mana_hash_get(self, "foo") == NULL);

	mana_hash_destroy(self);
}

static void test_mana_stack()
{
	mana_stack* self = mana_stack_create();

	/* 整数 */
	mana_stack_push_integer(self, 722);
	tinytest_assert(mana_stack_get_size(self) == sizeof(int) / sizeof(void*));
	tinytest_assert(mana_stack_get_integer(self, 0) == 722);
	mana_stack_set_integer(self, 0, 126);
	tinytest_assert(mana_stack_pop_integer(self) == 126);

	/* 実数 */
	mana_stack_push_real(self, 722);
	tinytest_assert(mana_stack_get_size(self) == sizeof(float) / sizeof(void*));
	tinytest_assert(mana_stack_get_real(self, 0) == 722);
	mana_stack_set_real(self, 0, 126);
	tinytest_assert(mana_stack_pop_real(self) == 126);

	/* 文字列 */
	char* test_message1 = "Hello, Mana";
	char* test_message2 = "Good luck, Mana";
	mana_stack_push_string(self, test_message1);
	tinytest_assert(mana_stack_get_size(self) == sizeof(const char*) / sizeof(void*));
	tinytest_assert(mana_stack_get_string(self, 0) == test_message1);
	mana_stack_set_string(self, 0, test_message2);
	tinytest_assert(mana_stack_pop_string(self) == test_message2);

	/* ポインタ */
	mana_stack_push_pointer(self, test_message1);
	tinytest_assert(mana_stack_get_size(self) == sizeof(const char*) / sizeof(void*));
	tinytest_assert(mana_stack_get_pointer(self, 0) == test_message1);
	mana_stack_set_pointer(self, 0, test_message2);
	tinytest_assert(mana_stack_pop_pointer(self) == test_message2);

	/* データ */
	unsigned char test_data[16] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf };
	unsigned char result_data[16];
	mana_stack_push_data(self, test_data, sizeof(test_data));
	tinytest_assert(mana_stack_get_size(self) == sizeof(test_data) / sizeof(void*));
	tinytest_assert(memcmp(test_data, mana_stack_get_address(self, sizeof(test_data) / sizeof(void*)), sizeof(test_data)) == 0);
	mana_stack_pop_data(self, result_data, sizeof(result_data));
	tinytest_assert(memcmp(result_data, test_data, sizeof(test_data)) == 0);

	/* 複製と削除 */
	mana_stack_push_pointer(self, test_message1);
	mana_stack_duplicate(self);
	mana_stack_remove(self, sizeof(const char*) / sizeof(void*));
	tinytest_assert(mana_stack_pop_pointer(self) == test_message1);
	tinytest_assert(mana_stack_get_size(self) == 0);

	/* 比較 */
	{
		mana_stack* dummy = mana_stack_create();
		mana_stack_push_data(dummy, test_data, sizeof(test_data));
		mana_stack_push_data(self, test_data, sizeof(test_data));
		tinytest_assert(mana_stack_compare(self, dummy) == 0);
		mana_stack_destroy(dummy);
		mana_stack_clear(self);
		tinytest_assert(mana_stack_get_size(self) == 0);
	}

	/* スタックポインタを移動 */
	mana_stack_set_size(self, 10);
	tinytest_assert(mana_stack_get_size(self) == 10);

	/* アドレス
	extern void* mana_stack_pop_address(mana_stack* self);
	*/

	mana_stack_destroy(self);
}

static void test_mana_stream()
{
	mana_stream* self = mana_stream_create();
	size_t total = 0;

	mana_stream_push_char(self, 'S');
	total += sizeof(char);
	tinytest_assert(mana_stream_get_used_size(self) == total);
	tinytest_assert(mana_stream_get_char(self) == 'S');
	tinytest_assert(mana_stream_pop_char(self) == 'S');

	mana_stream_push_short(self, 1209);
	total += sizeof(short);
	tinytest_assert(mana_stream_get_used_size(self) == total);
	tinytest_assert(mana_stream_get_short(self) == 1209);
	tinytest_assert(mana_stream_pop_short(self) == 1209);

	mana_stream_push_integer(self, 19800722);
	total += sizeof(int);
	tinytest_assert(mana_stream_get_used_size(self) == total);
	tinytest_assert(mana_stream_get_integer(self) == 19800722);
	tinytest_assert(mana_stream_pop_integer(self) == 19800722);

	mana_stream_push_unsigned_char(self, 0xFF);
	total += sizeof(unsigned char);
	tinytest_assert(mana_stream_get_used_size(self) == total);
	tinytest_assert(mana_stream_get_unsigned_char(self) == 0xFF);
	tinytest_assert(mana_stream_pop_unsigned_char(self) == 0xFF);

	mana_stream_push_unsigned_short(self, 0x0126);
	total += sizeof(unsigned short);
	tinytest_assert(mana_stream_get_used_size(self) == total);
	tinytest_assert(mana_stream_get_unsigned_short(self) == 0x0126);
	tinytest_assert(mana_stream_pop_unsigned_short(self) == 0x0126);

	mana_stream_push_unsigned_integer(self, 0x20081209);
	total += sizeof(unsigned int);
	tinytest_assert(mana_stream_get_used_size(self) == total);
	tinytest_assert(mana_stream_get_unsigned_integer(self) == 0x20081209);
	tinytest_assert(mana_stream_pop_unsigned_integer(self) == 0x20081209);

	mana_stream_push_float(self, 1972.0126f);
	total += sizeof(float);
	tinytest_assert(mana_stream_get_used_size(self) == total);
	tinytest_assert(mana_stream_get_float(self) == 1972.0126f);
	tinytest_assert(mana_stream_pop_float(self) == 1972.0126f);

	{
		char text[] = "Hello! My name is Sumitaka MORIYA. Nice to meet you!";
		char buffer[sizeof(text)];

		mana_stream_push_string(self, text);
		total += sizeof(text);
		tinytest_assert(mana_stream_get_used_size(self) == total);

		tinytest_assert(strcmp(text, mana_stream_get_string_pointer(self)) == 0);
		tinytest_assert(strlen(text) == mana_stream_get_string_length(self));

		mana_stream_get_string(self, buffer, sizeof(buffer));
		tinytest_assert(strcmp(text, buffer) == 0);

		mana_stream_pop_string(self, buffer, sizeof(buffer));
		tinytest_assert(strcmp(text, buffer) == 0);


		mana_stream_push_data(self, text, sizeof(text));

		mana_stream_get_data(self, buffer, sizeof(text));
		tinytest_assert(memcmp(text, buffer, sizeof(buffer)) == 0);

		mana_stream_pop_data(self, buffer, sizeof(text));
		tinytest_assert(memcmp(text, buffer, sizeof(buffer)) == 0);
	}

	mana_stream_rewind(self);

	mana_steram_seek(self, 1);

	mana_stream_destroy(self);
}

void tinytest_initialize(void)
{
	tinytest_regist_function(test_mana_array);
	tinytest_regist_function(test_mana_buffer);
	tinytest_regist_function(test_mana_frame);
	tinytest_regist_function(test_mana_hash);
	tinytest_regist_function(test_mana_stack);
	tinytest_regist_function(test_mana_stream);
}

void tinytest_finalize(void)
{
}
